﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;

using System.IO.Ports; //加入串口
using System.Text.RegularExpressions;//正则表达式，加入命名空间。

namespace 串口上位机
{
    public partial class Serial : Form
    {
        SerialPort sp = null;
        private bool isOpen = false;
        private bool isSetProperty = false;
        private int reciveCount = 0;

        public Serial()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            this.MaximizeBox = false;
            this.MaximumSize = this.Size;
            this.MinimumSize = this.Size;
            for (int i = 0; i < 10; i++)
            {
                cB_UsartCom.Items.Add("COM" + (i + 1).ToString());
            }
            cB_UsartCom.SelectedIndex = 0;

            cB_UsartBruad.Items.Add("1200");
            cB_UsartBruad.Items.Add("2400");
            cB_UsartBruad.Items.Add("4800");
            cB_UsartBruad.Items.Add("9600");
            cB_UsartBruad.Items.Add("19200");
            cB_UsartBruad.Items.Add("38400");
            cB_UsartBruad.Items.Add("115200");
            cB_UsartBruad.SelectedIndex = 6;

            cB_UsartDataBit.Items.Add("8");
            cB_UsartDataBit.Items.Add("7");
            cB_UsartDataBit.Items.Add("6");
            cB_UsartDataBit.Items.Add("5");
            cB_UsartDataBit.SelectedIndex = 0;

            cB_UsartStopBit.Items.Add("0");
            cB_UsartStopBit.Items.Add("1");
            cB_UsartStopBit.Items.Add("1.5");
            cB_UsartStopBit.Items.Add("2");
            cB_UsartStopBit.SelectedIndex = 1;

            cB_UsartCRCBit.Items.Add("无");
            cB_UsartCRCBit.Items.Add("奇校验");
            cB_UsartCRCBit.Items.Add("偶校验");
            cB_UsartCRCBit.SelectedIndex = 0;

            rbnChar.Checked = true; //默认使用字符显示
            /*添加时间显示*/
            this.toolStripStatusLabel1.Text = "当前时间" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
            timer1.Interval = 1000;
            timer1.Start();

        }

        private void btn_find_Click(object sender, EventArgs e)
        {
            bool comExistence = false;
            cB_UsartCom.Items.Clear();
            for (int i = 0; i < 10; i++) //寻找串口
            {
                try
                {
                    SerialPort sp = new SerialPort("COM" + (i + 1).ToString());
                    sp.Open();
                    sp.Close();
                    cB_UsartCom.Items.Add("COM" + (i + 1).ToString());
                    comExistence = true;
                }

                catch (Exception)
                {
                    continue;
                }
            }
            if (comExistence)
            {
                cB_UsartCom.SelectedIndex = 0;
            }
            else
            {
                MessageBox.Show("没有找到可用串口！", "错误提示！");
            }
        }
        private bool CheckPortSetting()
        {
            if (cB_UsartCom.Text.Trim() == "") return false;
            if (cB_UsartBruad.Text.Trim() == "") return false;
            if (cB_UsartStopBit.Text.Trim() == "") return false;
            if (cB_UsartCRCBit.Text.Trim() == "") return false;
            if (cB_UsartDataBit.Text.Trim() == "") return false;
            return true;
        }
        private bool CheckSendData()
        {
            if (tbxSendData.Text.Trim() == "") return false;
            return true;
        }

        private void SetProperty()
        {
            sp = new SerialPort();
            sp.PortName = cB_UsartCom.Text.Trim();
            sp.BaudRate = Convert.ToInt32(cB_UsartBruad.Text.Trim());
            if (cB_UsartStopBit.Text.Trim() == "0")
            {
                sp.StopBits = StopBits.None;
            }
            else if (cB_UsartStopBit.Text.Trim() == "1.5")
            {
                sp.StopBits = StopBits.OnePointFive;
            }
            else if (cB_UsartStopBit.Text.Trim() == "2")
            {
                sp.StopBits = StopBits.Two;
            }
            else
            {
                sp.StopBits = StopBits.One;
            }

            sp.DataBits = Convert.ToInt16(cB_UsartDataBit.Text.Trim());

            if (cB_UsartCRCBit.Text.Trim() == "奇校验")
            {
                sp.Parity = Parity.Odd;

            }
            else if (cB_UsartCRCBit.Text.Trim() == "偶校验")
            {
                sp.Parity = Parity.Even;
            }
            else
            {
                sp.Parity = Parity.None;
            }
            sp.ReadTimeout = -1;
            sp.RtsEnable = true;

            sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);


        }
        private void sp_DataReceived(object sender, SerialDataReceivedEventArgs eg)
        {

            System.Threading.Thread.Sleep(100); //使用线程的方式

            this.Invoke((EventHandler)delegate//异步执行 一个线程
            {
                if (!rbnHex.Checked)//如果未选中name为rbnHex的控件
                {
                    tbxRecvData.Text += sp.ReadLine();
                    StringBuilder sb = new StringBuilder();
                    long rec_count = 0;
                    int num = sp.BytesToRead;
                    byte[] recbuf = new byte[num];
                    rec_count += num;

                    sp.Read(recbuf, 0, num);
                    sb.Clear();
                    reciveCount += recbuf.Length;
                    toollabelRXCount.Text = reciveCount.ToString(); //刷新接收的数据
                    try
                    {
                        Invoke((EventHandler)(delegate // 使用委托的方法
                        {
                            sb.Append(Encoding.ASCII.GetString(recbuf));  //将整个数组解码为ASCII数组
                            sb.Replace("\0", "\\0"); //使用\0使用 \\0显示出来
                            tbxRecvData.AppendText(sb.ToString());
                        }
                        ));
                    }


                    catch
                    {
                        MessageBox.Show("请勾选换行", "错误提示");
                    }
                }
                else if (rbnHex.Checked)//如果选中
                {
                    Byte[] ReceivedData = new Byte[sp.BytesToRead];
                    sp.Read(ReceivedData, 0, ReceivedData.Length);

                    String RecvDataText = null;

                    for (int i = 0; i < ReceivedData.Length; i++)
                    {
                        RecvDataText += (ReceivedData[i].ToString("X2") + " ");//数组里接收到的数据转化为16进制
                    }
                    tbxRecvData.Text += RecvDataText;
                }
                sp.DiscardInBuffer();
            });
        }


        private void btn_open_Click(object sender, EventArgs e)
        {
            if (isOpen == false) //串口未打开的状态
            {
                if (!CheckPortSetting())
                {
                    MessageBox.Show("串口未设置", "错误提醒");
                    return;
                }
                if (!isSetProperty)
                {
                    SetProperty();
                    isSetProperty = true;
                }
                try //查看串口是否打开
                {
                    sp.Open();
                    isOpen = true;
                    btn_open.Text = "关闭串口";
                    cB_UsartCom.Enabled = false;
                    cB_UsartBruad.Enabled = false;
                    cB_UsartDataBit.Enabled = false;
                    cB_UsartStopBit.Enabled = false;
                    cB_UsartCRCBit.Enabled = false;
                    rbnChar.Enabled = false;
                    rbnHex.Enabled = false;
                }
                catch (Exception)
                {
                    isSetProperty = false;
                    isOpen = false;
                    MessageBox.Show("串口无效或已被占用", "错误提示");
                }
            }
            else if(isOpen == true)
            {
                try //查看串口是否关闭
                {

                    if (!timeBox.Checked)
                    {
                        sp.Close(); //关闭端口
                        isOpen = false;
                        btn_open.Text = "打开串口";
                        cB_UsartCom.Enabled = true;
                        cB_UsartBruad.Enabled = true;
                        cB_UsartDataBit.Enabled = true;
                        cB_UsartStopBit.Enabled = true;
                        cB_UsartCRCBit.Enabled = true;
                        rbnChar.Enabled = true;
                        rbnHex.Enabled = true;
                        numericUpDown1.Value = 0;

                    }
                    else
                    {
                        MessageBox.Show("请先关闭自动发送", "错误提醒");                
                    }
                }
                catch (Exception)
                {
                    MessageBox.Show("关闭串口时发生错误", "错误提示");
                }
            }
        }

        private void btn_send_Click(object sender, EventArgs e)
        {
            byte[] textchar = new byte[1];
            int num = 0;
            if (isOpen)
            {
                try
                {
                    if (!checkBoxHex.Checked)//是否选择HEX发送
                    {
                        if (!checkBoxLine.Checked)//是否选择回车换行
                        {
                            sp.Write(tbxSendData.Text);
                        }
                        else
                        {
                            string res = tbxSendData.Text + "\r\n";
                            byte[] byteArray = System.Text.Encoding.Default.GetBytes(res);
                            sp.Write(byteArray, 0, byteArray.Length);
                            //toollabelTXCount.Text = tbxSendData.Text.ToString();
                        }
                    }
                    else // 选择HEX发送
                    {
                        string buf = tbxSendData.Text;
                        string bartenm = @"\s"; // 正则表达式	与任何空白字符匹配。
                        string replace = "";

                        Regex rgx = new Regex(bartenm); //表示不可变的正则表达式
                        string sendData = rgx.Replace(buf, replace);//代替正则表达式
                        num = (sendData.Length - sendData.Length % 2) / 2;
                        for (int i = 0; i < num; i++)
                        {
                            textchar[0] = Convert.ToByte(sendData.Substring(i * 2, 2), 16);
                            sp.Write(textchar, 0, 1);

                        }

                        if (sendData.Length % 2 != 0)
                        {
                            textchar[0] = Convert.ToByte(sendData.Substring(tbxSendData.Text.Length - 1, 2), 16);
                            sp.Write(textchar, 0, 1);
                            num++;

                        }
                    }
                }
                catch (Exception)
                {
                    MessageBox.Show("发送数据时发生错误！", "错误提示");
                    return;
                }

            }
            else 
            {
                MessageBox.Show("串口未打开错误提示！", "错误提示");
            }
            if (!CheckSendData())
            {
                MessageBox.Show("请输入要发送的数据", "错误提示");
            }

        }
        private void btn_clearRX_Click(object sender, EventArgs e)
        {

                tbxRecvData.Text = ""; //清空数据
        }
        private void btn_clearTX_Click(object sender, EventArgs e)
        {
                tbxSendData.Text = ""; //清空数据
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            this.toolStripStatusLabel1.Text = "当前时间：" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
        }

        private void timeBox_CheckedChanged(object sender, EventArgs e)
        {

            System.Windows.Forms.Timer txTimer = new System.Windows.Forms.Timer();//获取时间
            if (timeBox.Checked) //检查自动发送是否按下
            {
                if (numericUpDown1.Value != 0)
                {
                    if (CheckSendData())
                    {
                        txTimer.Enabled = false;
                        timer2.Interval = (int)numericUpDown1.Value; //定时器赋初值  
                        timer2.Start(); //使用定时器2来计算时间来自动发送
                    }
                    else if (!CheckSendData())
                    {
                        timer2.Stop();
                    }
                }
                else if (numericUpDown1.Value == 0)
                {
                    timer2.Stop();
                }
            }
            else
            {
                txTimer.Enabled = true;
                timer2.Stop();
            }
        }
        private void timer2_Tick(object sender, EventArgs e)
        {
            btn_send_Click(btn_send, new EventArgs());

        }

        private void btn_chart_Click(object sender, EventArgs e)
        {

        }
    }
}
